package org.smartagents.enviro;

import org.smartagents.body.Body;
import org.smartagents.global.Global;
import org.smartagents.global.GlobalConstants;
import org.smartagents.global.Identifiable;
import org.smartagents.util.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

public class Environment implements Runnable {

    private List<Identifiable> knownElements = new ArrayList<Identifiable>();
    private Map<String, Identifiable> identifiableMap = new HashMap<String, Identifiable>();

    public void addBody(Identifiable body) {
        knownElements.add(body);
        identifiableMap.put(body.getX() + "," + body.getY(), body);
    }


    public Environment() {
        Global.getInstance().setEnvironment(this);
    }

    private int getDirection(int dir, int rotation) {
        int val = dir * 10 + rotation;

        switch (val) {
            case (12):
                return 4;
            case (22):
                return 3;
            case (32):
                return 1;
            case (42):
                return 2;
            case (13):
                return 2;
            case (23):
                return 1;
            case (33):
                return 4;
            case (43):
                return 3;
            case (14):
                return 3;
            case (24):
                return 4;
            case (34):
                return 2;
            case (44):
                return 1;
            default:
                return 0;
        }
    }

    public String getNeighbors(Identifiable identifiable, int direction, Integer length) {
        Identifiable searchFor;
        int xinc = 0;
        int yinc = 0;

        int rotation = 1;
        if (identifiable instanceof Body) {
            rotation = ((Body) identifiable).getRotation();
            if (rotation > 1) {
                direction = getDirection(direction, rotation);
            }

        }

        if (direction == EnvironmentConstants.EAST) {
            xinc = 1;
        } else if (direction == EnvironmentConstants.WEST) {
            xinc = -1;
        } else if (direction == EnvironmentConstants.SOUTH) {
            yinc = 1;
        } else if (direction == EnvironmentConstants.NORTH) {
            yinc = -1;
        }

        for (int i = 1; i <= length; i++) {

            String location = (identifiable.getX() + (xinc * i)) + "," + (identifiable.getY() + (yinc * i));
            searchFor = identifiableMap.get(location);
            if (searchFor != null) {
                Logger.logExtreme("Found " + searchFor + " at " + i + " from " + identifiable.getX() + " " + identifiable.getY());
                return searchFor.identify();
            }
        }
        return null;
    }

    public void rotateBody(Identifiable id, int dir) {
        Body body = (Body) id;
        body.setRotation(body.getRotation() + dir);
    }

    public void moveBody(Identifiable body, int direction) {
        String location = body.getX() + "," + body.getY();


        int rotation = 1;
        if (body instanceof Body) {
            rotation = ((Body) body).getRotation();
            if (rotation > 1) {
                direction = getDirection(direction, rotation);
            }

        }
        int newX = body.getX();
        int newY = body.getY();
        switch (direction) {
            case 1:
                newX = body.getX() + 1;
                break;
            case 2:
                newX = body.getX() - 1;
                break;
            case 3:
                newY = body.getY() - 1;
                break;
            case 4:
                newY = body.getY() + 1;
                break;
            default:
                System.out.println("Errror unable to move: " + body.identify() + " " + direction);
        }

        if (identifiableMap.containsKey(newX + "," + newY)) {
            System.out.println("UnableToMove");
        } else {
            body.setX(newX);
            body.setY(newY);
            identifiableMap.remove(location);
            location = body.getX() + "," + body.getY();
            identifiableMap.put(location, body);
        }

    }

    public void run() {
        while (Global.getInstance().isRun()) {
            for (Identifiable element : knownElements) {
                element.doTick();

            }
            try {
                Thread.currentThread().sleep(GlobalConstants.TICK_DELAY);
            } catch (InterruptedException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    public Map<String, Identifiable> getIdentifiableMap() {
        return identifiableMap;
    }
}
